package edu.pku.sei.pgie.persistence.graph;

import java.io.File;
import java.io.FileWriter;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.Iterator;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import edu.pku.sei.pgie.analyzer.core.Context;
import edu.pku.sei.pgie.analyzer.core.ICollector;
import edu.pku.sei.pgie.analyzer.internal.Metrics;
import edu.pku.sei.pgie.beans.CodeEntity;
import edu.pku.sei.pgie.beans.Link;
import edu.pku.sei.pgie.beans.Structure;
import edu.pku.sei.pgie.persistence.PersistenceException;

public class GraphCollector implements ICollector {
    private static Log logger = LogFactory.getLog(GraphCollector.class);

    Context context;

    PrintWriter entityWriter;

    PrintWriter linkWriter;

    PrintWriter structureWriter;

    PrintWriter metricsWriter;

    long codeIdSeed = 0;

    long linkIdSeed = 0;

    long structureIdSeed = 0;

    HashMap<String,Long> codeEntityMap;

    public GraphCollector(Context context) throws PersistenceException {
        this.context = context;
        if (context.getOutputDir() == null
                || context.getOutputDir().length() == 0)
            throw new PersistenceException("invalid output dir");
        if (!new File(context.getOutputDir()).exists()) {
            throw new PersistenceException("invalid output dir");
        }
        this.codeEntityMap = new HashMap<String,Long>();
        File outputDir = new File(context.getOutputDir());
        try {
            entityWriter = new PrintWriter(new FileWriter(new File(outputDir,
                    "entity.dat")));
            linkWriter = new PrintWriter(new FileWriter(new File(outputDir,
                    "link.dat")));
            structureWriter = new PrintWriter(new FileWriter(new File(
                    outputDir, "structure.dat")));
            metricsWriter = new PrintWriter(new FileWriter(new File(outputDir,
                    "metrics.dat")));
        } catch (Exception e) {
            throw new PersistenceException(e);
        }
    }

    public void collect(Structure structure) {
        for (Iterator iter = structure.getChildren().iterator(); iter.hasNext();) {
            Structure child = (Structure) iter.next();
            structureWriter.println(child.getId()+","+structure.getName()+","+
                    child.getName());
        }
    }

    public void collect(Link link) {
        linkWriter.println(nextLinkId() + "," + link.getStartPoint() + ","
                + link.getEndPoint() + "," + link.getType());
    }

    public void collect(CodeEntity codeEntity) {
        entityWriter.println(codeEntity.getCodeId() + "," + codeEntity.getFqn()
                + "," + codeEntity.getEntityType() + ","
                + codeEntity.getLocation() + "," + codeEntity.getContext()
                + "," + codeEntity.getRank());
        this.codeEntityMap.put(codeEntity.getFqn(), codeEntity.getCodeId());
    }

    public void close() {
        try {
            entityWriter.close();
            linkWriter.close();
            structureWriter.close();
            metricsWriter.close();
        } catch (Exception e) {
            logger.debug("close output stream exception", e);
        }
    }

    public void collect(Metrics metrics) {
        metricsWriter.print(metrics.toString());
    }

    public synchronized long nextCodeId() {
        return codeIdSeed++;
    }

    public synchronized long nextLinkId() {
        return linkIdSeed++;
    }

    public synchronized long nextStructureId() {
        return structureIdSeed++;
    }

}
